<script lang="ts" setup>
import { ref, reactive, toRefs, onMounted, watch } from "vue";
import {
  SuccessFilled,
  WarningFilled,
  CircleCloseFilled,
} from "@element-plus/icons-vue";
import {
  SelectSubjectType,
  DrawerInfoType,
  DrawerItemType,
  DrawerInfoTypePartOptions,
} from "./types";
import { ElDrawer, ElMessage } from "element-plus";
import { isEmptyObject } from "@/utils";
import { useCompRef } from "@/utils/hooks";
import { SubjectStatusEnum } from "@/enum/question-test/QuestionTestEnum";

export interface DrawerSubjectExpose {
  show: (v: boolean) => void;
}

type DrawerItems = DrawerInfoTypePartOptions<
  DrawerInfoType,
  "size" | "limit" | "total"
>;

const props = defineProps({
  subjects: {
    type: Array<SelectSubjectType>,
    default: () => [],
  },
  total: {
    type: Number,
    default: 0,
  },
});

const emits = defineEmits<{
  (e: "onSlideTo", index: number): void;
}>();

const DrawerRef = useCompRef(ElDrawer);
const loading = ref(false);
// 定义抽屉选项面板信息
const drawerInfo = reactive<DrawerInfoType>({
  activeName: "",
  // 是否显示
  show: false,
  // 根据当前总试题数，显示多少条抽屉选项
  size: 5,
  // 总试题数
  total: 0,
  // 一个抽屉选项对应多少题
  limit: 100,
  // 子项数据
  drawerItems: [],
  // 文档片段
  fragmentsItems: [],
});
// 答题情况
const answerStatus = reactive<Record<string, number>>({
  // 答对的试题
  correct: 0,
  // 答错的试题
  error: 0,
  // 未答的试题
  unanswered: 0,
});

const { subjects } = toRefs(props);
const { size, limit, total, activeName, fragmentsItems } = toRefs(drawerInfo);

// 监听总试题数变化
watch(
  () => props.total,
  (newVal) => {
    drawerInfo.total = newVal ?? 0;
  },
  { deep: true, immediate: true }
);

onMounted(() => {
  // 初始化数据
  init();
});

// 显示抽屉选项卡
function show(v: boolean) {
  drawerInfo.show = v;
}

function init() {
  // 计算需要显示多少个抽屉选项卡（向上取整）
  size.value = Math.ceil(total.value / limit.value);
  // 计算抽屉选项卡数据
  drawerInfo.drawerItems = generateDrawerItems({
    size: size.value,
    limit: limit.value,
    total: total.value,
  });
  // console.log("抽屉选项卡数据==>", drawerInfo.drawerItems);
  // 通过文档片段生成选项
  fragmentsItems.value = generateSubjects(drawerInfo.drawerItems);
}

/**
 * 生成答题卡选项
 * @param items 抽屉选项卡数据
 */
function generateSubjects(items: DrawerItemType[]) {
  // 文档片段数组
  const fragments: Array<DocumentFragment> = [];
  items.forEach((item) => {
    // 创建文档片段
    const fragment = document.createDocumentFragment();
    // 循环生成选项卡
    for (let j = item.start; j <= item.last; j++) {
      const type = generateType(subjects.value[j]);
      // 生成html结构
      const div = document.createElement("div");
      div.addEventListener("click", () => {
        handleClickSubjectItem(j);
      });
      div.classList.add("item", `type-${type}`);
      div.innerHTML = `${j}`;
      // 追加到文档片段
      fragment.appendChild(div);
    }
    // 追加到文档片段数组
    fragments.push(fragment);
  });
  return fragments;
}

/**
 *
 * @param index 选项卡索引，注意这里是从`1`开始的
 */
function handleClickSubjectItem(index: number) {
  emits("onSlideTo", index - 1);
}

/**
 * 计算抽屉选项卡数据
 * @param obj 选项卡数据对象
 */
function generateDrawerItems(obj: DrawerItems) {
  const result = [];
  for (let i = 1; i <= obj.size; i++) {
    const newItem: DrawerItemType = {
      name: "",
      title: "",
      start: 0,
      last: 0,
    };
    newItem.name = i.toString();
    if (i * obj.limit <= obj.total) {
      newItem.last = i * obj.limit;
    } else {
      newItem.last = obj.total;
    }
    newItem.start = (i - 1) * obj.limit + 1;

    newItem.title = `第${i}阶段${newItem.start}-${newItem.last}题`;
    result.push(newItem);
  }
  return result;
}

/**
 * 根据答题卡数据生成答题卡类型
 * @param obj 答题卡数据对象
 * 答错：0，答对：1，未答：2
 */
function generateType(obj: SelectSubjectType) {
  if (isEmptyObject(obj)) return 2;
  if (!obj.target.length) {
    return 2;
  }
  if (obj.status) {
    return 1;
  }
  return 0;
}

// el-drawer打开时触发
const handleDrawerOpen = () => {
  const contents = document.querySelectorAll(
    ".custom-drawer .el-collapse .content"
  ) as NodeListOf<HTMLElement>;

  createFragmentToContent(contents);

  // TODO：待优化
  const correct = subjects.value.filter(
    (item) => item.status === SubjectStatusEnum.CORRECT
  );
  const wrong = subjects.value.filter(
    (item) => item.status === SubjectStatusEnum.ERROR
  );
  const unanswered = subjects.value.filter(
    (item) => item.status === SubjectStatusEnum.NOT_DONE
  );
  answerStatus.correct = correct.length;
  answerStatus.error = wrong.length;
  answerStatus.unanswered = unanswered.length;

  // 每次打开答题卡，都更新答题情况
  correct.map((item) => activateSubjectItem(contents, item));
  wrong.map((item) => activateSubjectItem(contents, item));
};

/**
 * 根据对错激活对应选项
 * @param dom drawer下面动态生成的content父节点
 * @param item 答题卡数据对象
 */
function activateSubjectItem(
  dom: NodeListOf<HTMLElement>,
  subject: SelectSubjectType
) {
  if (!dom.length) {
    console.error("contents-DOM节点为空");
    return;
  }
  const stage = dom[Math.floor(subject.index / limit.value)];
  if (!stage) {
    ElMessage.error(`stage：${stage}`);
  }
  const child = stage.children[subject.index % limit.value] ?? [];
  if (!child) {
    ElMessage.error(`child：${child}`);
  }

  // 先移除未答类名，再根据type添加对应类名，答对或者答错
  child.classList.remove("type-2");
  child.classList.add(`type-${subject.status}`);
}

// 只追加一次文档片段，就是onMounted的时候
function createFragmentToContent(dom: NodeListOf<HTMLElement>) {
  // 判断是否追加过子元素
  if ((dom[0] && dom[0].children.length > 0) || !fragmentsItems.value.length) {
    return;
  }
  for (let i = 0; i < dom.length; i++) {
    dom[i].appendChild(fragmentsItems.value[i]);
  }
}

const handleClose = (done: () => void) => {
  done();
};

defineExpose({
  show,
});

defineOptions({
  name: "DrawerSubject",
});
</script>

<template>
  <div
    class="drawer-subject"
    v-loading.fullscreen.lock="loading"
    element-loading-text="🥭答题卡加载中..."
  >
    <el-drawer
      ref="DrawerRef"
      size="70%"
      lock-scroll
      v-if="subjects.length"
      v-model="drawerInfo.show"
      class="custom-drawer"
      title="🍤答题卡"
      direction="btt"
      :before-close="handleClose"
      @open="handleDrawerOpen"
    >
      <div class="tip-btn">
        <el-button
          size="large"
          color="#F8F8F8"
          type="success"
          :icon="SuccessFilled"
          ><span style="margin: 0 3px">答对</span>
          <span class="count">{{ answerStatus.correct }}</span></el-button
        >
        <el-button
          size="large"
          color="#F8F8F8"
          type="danger"
          :icon="CircleCloseFilled"
          ><span style="margin: 0 3px">答错</span>
          <span class="count">{{ answerStatus.error }}</span></el-button
        >
        <el-button
          size="large"
          color="#F8F8F8"
          type="warning"
          :icon="WarningFilled"
          ><span style="margin: 0 3px">未答</span>
          <span class="count">{{ answerStatus.unanswered }}</span></el-button
        >
      </div>

      <el-collapse v-model="activeName" accordion class="collapse">
        <el-collapse-item
          v-for="item in drawerInfo.drawerItems"
          :key="item.name"
          :title="item.title"
          :name="item.name"
        >
          <!-- 通过文档片段动态生成选项卡 -->
          <div class="content"></div>
        </el-collapse-item>
      </el-collapse>
    </el-drawer>
  </div>
</template>

<style lang="scss" scoped>
.drawer-subject {
  :deep(.custom-drawer) {
    .el-drawer__header {
      border-bottom: 1px solid #eee;
      padding-bottom: 20px;
      margin-bottom: 0;
    }
    .tip-btn {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 10px;
      margin-bottom: 20px;
      .count {
        font-weight: bold;
        color: #000;
        font-size: 21px;
      }
    }
  }

  :deep(.tip-btn) {
    .el-button {
      padding: 0;
      & > span {
        color: #747373;
        font-size: 12.5px;
        font-weight: 100;
      }

      .el-icon {
        font-size: 18px;
      }
      &:first-child {
        color: #01c47d;
      }
      &:nth-child(2) {
        color: #ff5722;
      }
      &:last-child {
        color: #e6a23c;
      }
    }
  }

  :deep(.collapse) {
    .el-collapse-item {
      .el-collapse-item__header {
        padding: 0 5px;
      }

      .el-collapse-item__wrap .el-collapse-item__content {
        padding: 0 5px;
      }
    }
    .content {
      display: grid;
      grid-template-columns: repeat(6, 1fr);
      gap: 10px;
      padding-bottom: 15px;
      justify-items: center;
      align-content: center;
      .item {
        width: 50px;
        height: 50px;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
        font-weight: 100;
      }
      // 答错
      .type-0 {
        font-weight: bold;
        color: rgb(228, 25, 28);
        background-color: rgba(255, 245, 244, 1);
      }
      // 答对
      .type-1 {
        font-weight: bold;
        color: rgb(8, 202, 131);
        background-color: rgba(236, 255, 249);
      }
      // 未答
      .type-2 {
        font-weight: bold;
        color: black;
        background-color: #fff;
        border: 1px solid #dbdbdb;
      }
    }

    @media screen and (max-width: 300px) {
      .content {
        grid-template-columns: repeat(4, 1fr);
      }
    }
    @media screen and (max-width: 400px) {
      .content {
        grid-template-columns: repeat(5, 1fr);
      }
    }

    @media screen and (min-width: 500px) and (max-width: 600px) {
      .content {
        grid-template-columns: repeat(6, 1fr);
      }
    }

    @media screen and (min-width: 700px) and (max-width: 900px) {
      .content {
        grid-template-columns: repeat(8, 1fr);
      }
    }

    @media screen and (min-width: 1000px) and (max-width: 1200px) {
      .content {
        grid-template-columns: repeat(9, 1fr);
      }
    }
  }
}
</style>
